package com.atguigu.gmall.order.service;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClient;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.CartInfoMapper;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
public class OrderInfoServiceImpl implements OrderInfoService {
    @Autowired
    private ProductFeignClient productFeignClient;

    //2.校验库存
    @Override
    public boolean hasStock(OrderDetail orderDetail) {
        boolean flag = "1".equals(HttpClientUtil.doGet("http://www.gware.com:9001/hasStock?skuId=" +
                orderDetail.getSkuId() + "&num=" + orderDetail.getSkuNum()));
        return flag;
    }

    //3.提交订单(保存订单主表,订单详情表)
    @Override
    public Long insertOrder(OrderInfo orderInfo) {
        //3.提交订单(保存订单主表,订单详情表)
        //3.1 保存订单主表
        //刚提交订单状态 未付钱
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        //orderInfo.setOrderStatus(OrderStatus.UNPAID.getComment());//要文字的

        //订单交易编号
        String outTradeNo = "ATGUIGU" + System.currentTimeMillis() + new Random().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);
        //订单描述 手机扫码的时候 在你的手机上显示
        StringBuilder tradeBody = new StringBuilder();
        //3.1 防止页面价格被篡改 需要重新查询单个商品的价格
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        if (!CollectionUtils.isEmpty(orderDetailList)){
            for (OrderDetail orderDetail : orderDetailList) {
                BigDecimal price = productFeignClient.getPrice(orderDetail.getSkuId());
                orderDetail.setOrderPrice(price);
                tradeBody.append(orderDetail.getSkuName() + " ");
            }
        }

        //3.2总金额是需要重新计算的
        orderInfo.sumTotalAmount();
        //订单描述: 手机扫码的时候,在你手机上显示
        if (tradeBody.length() > 100){
            orderInfo.setTradeBody(tradeBody.substring(0,100));
        }else{
            orderInfo.setTradeBody(tradeBody.toString());
        }

        //设置当前时间和示效时间
        Calendar calendar = Calendar.getInstance();
        orderInfo.setCreateTime(calendar.getTime()); //当前时间
        calendar.add(Calendar.HOUR,2);
        orderInfo.setExpireTime(calendar.getTime()); //示效时间 未来两小时内
        //设置进度状态
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        //1.保存订单表: 要保存订单表,才会有主键
        orderInfoMapper.insert(orderInfo);


        //2. 保存订单详情表  要先保存订单表,才会有外键
        List<String> delRedis = new ArrayList<>(orderDetailList.size());//删除redis  skuId集合
        List<Long> delDb = new ArrayList<>(orderDetailList.size()); //删除db  skuId集合
        orderDetailList.forEach(orderDetail -> {
            //设置外键
            orderDetail.setOrderId(orderInfo.getId());
            //把订单详情添加到详情表
            orderDetailMapper.insert(orderDetail);
            //把skuId添加到delRedis集合中
            delRedis.add(orderDetail.getSkuId().toString());
            //把skuId添加到delDb集合中
            delDb.add(orderDetail.getSkuId());  //删除数据库中的数据必须使用对应的Long类型 不然索引使用查询效率低
        });

        /*
        将第4步,和第5步注释掉,测试方便


        //4.将下的订单中的商品从购物车中移除 使用多线程异步编排
        //4.1 redis
        String cacheHKey = RedisConst.USER_KEY_PREFIX + orderInfo.getUserId() +
                RedisConst.USER_CART_KEY_SUFFIX;
        redisTemplate.opsForHash().delete(cacheHKey,delRedis.toArray()); //批量删除

        //4.2 保存DB
        CompletableFuture.runAsync(() -> {
            cartInfoMapper.delete(new QueryWrapper<CartInfo>()
            .eq("user_id",orderInfo.getUserId())
            .in("sku_id",delDb));
        },threadPoolExecutor);

        //5.开始计时,在规定时间内不给钱(2小时) 取消订单 支付宝二维码的默认有效时间2小时
        //生产者
        rabbitService.sendDelayMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL,
                MqConst.ROUTING_ORDER_CANCEL,orderInfo.getId(),MqConst.DELAY_TIME);


         */
        return orderInfo.getId();
    }

    //根据订单id查询订单对象
    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        return orderInfo;
    }

    //修改订单状态
    @Override
    public void updateOrderStatus(Long orderID, ProcessStatus processStatus) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderID);
        //修改订单状态  processStatus.PAID.getOrderStatus().name()
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        //修改进度状态
        orderInfo.setProcessStatus(processStatus.name());
        orderInfoMapper.updateById(orderInfo); //更新
    }


    //获取订单以及订单详情集合
    public OrderInfo getOrderInfoAndDetails(Long orderId){
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if (null != orderInfo){
            List<OrderDetail> detailList = orderDetailMapper.selectList(new QueryWrapper<OrderDetail>()
                    .eq("order_id", orderId));
            orderInfo.setOrderDetailList(detailList);
        }
        return orderInfo;
    }

    //初始化库存那边需要的数据
    @Override
    public Map initWareOrder(Long orderID) {
        OrderInfo orderInfo = this.getOrderInfoAndDetails(orderID);
        return initWareOrder(orderInfo);
    }

    //初始化库存那边需要的数据
    @Override
    public Map initWareOrder(OrderInfo orderInfo) {
        Map map = new HashMap();
        map.put("orderId",orderInfo.getId());
        map.put("consignee", orderInfo.getConsignee());
        map.put("consigneeTel", orderInfo.getConsigneeTel());
        map.put("orderComment", orderInfo.getOrderComment());
        map.put("orderBody", orderInfo.getTradeBody());
        map.put("deliveryAddress", orderInfo.getDeliveryAddress());
        map.put("paymentWay",orderInfo.getPaymentWay().equals("ONLINE")?"2":"1");
        //仓库的ID
        map.put("wareId",orderInfo.getWareId());

        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<Map> details = orderDetailList.stream().map(orderDetail -> {
            Map m = new HashMap();
            m.put("skuId", orderDetail.getSkuId());
            m.put("skuNum", orderDetail.getSkuNum());
            m.put("skuName", orderDetail.getSkuName());
            return m;
        }).collect(Collectors.toList());
        map.put("details",details);
        return map;
    }

    //1.开始拆单, 1张订单 拆分后 成n张订单 超级难
    // 首先要有一张原始订单   然后拆分后n个订单
    @Override
    public List<OrderInfo> orderSplit(Long orderId, String wareSkuMap) {
        //获得原始订单
        OrderInfo orderInfoOrigin = getOrderInfoAndDetails(orderId);
        //wareSkuMap  [{"wareId":"1","skuIds":["2","10"]}
        //                ,{"wareId":"2","skuIds":["3"]}]
        //将json字符串解析成List<Map>
        List<Map> wareSkuMapList = JSONObject.parseArray(wareSkuMap, Map.class);
        List<OrderInfo> subOrderInfoList = wareSkuMapList.stream().map(map -> {
            //子订单
            OrderInfo subOrderInfo = new OrderInfo();

            //将父订单中的所有属性直接复制给子订单,三项不能复制: id,parent_order_id,total_amount
            BeanUtils.copyProperties(orderInfoOrigin, subOrderInfo);
            //id
            subOrderInfo.setId(null);
            //parent_order_id
            subOrderInfo.setParentOrderId(orderInfoOrigin.getId());
            //仓库Id
            Object wareId = map.get("wareId");
            subOrderInfo.setWareId(String.valueOf(wareId));

            //TODO 总金额
            List<String> skuIds = (List<String>) map.get("skuIds");
            //获取原始订单表的订单详情
            List<OrderDetail> orderDetailList = orderInfoOrigin.getOrderDetailList();
            //过滤原始订单详情,得到子菜单的订单详情
            //wareSkuMap  [{"wareId":"1","skuIds":["2","10"]}
            //                ,{"wareId":"2","skuIds":["3"]}]
            List<OrderDetail> subOrderDetailList = orderDetailList.stream().filter(orderDetail -> {
                if (skuIds.contains(String.valueOf(orderDetail.getSkuId()))) {
                    return true;
                } else {
                    return false;
                }
            }).collect(Collectors.toList());
            //把子订单详情放入子订单主表中
            subOrderInfo.setOrderDetailList(subOrderDetailList);
            subOrderInfo.sumTotalAmount(); //直接调用pojo里面的方法设置总金额
            //将子订单信息保存到订单表中
            orderInfoMapper.insert(subOrderInfo);
            //修改子订单详情的外键 order_id
            subOrderDetailList.forEach(subOrderDetail -> {
                subOrderDetail.setOrderId(subOrderInfo.getId());
                orderDetailMapper.updateById(subOrderDetail); //能修改是因为orderDetail的id已经查询到了
            });
            return subOrderInfo;
        }).collect(Collectors.toList());
        //更新父订单中的状态为已拆单
        updateOrderStatus(orderInfoOrigin.getId(),ProcessStatus.SPLIT);

        return subOrderInfoList;
    }


    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;
}
